#include "at32f403a_407_wk_config.h"
#include "operate_spim.h"
#include <string.h>
#include "wk_system.h"



/**
  * @brief  init the spim flash
  * @param  none
  * @retval none
  */
void spim_init(void)
{
  gpio_init_type gpio_init_struct;

  /* enable the clock */
  crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);

  /* init spim io */
  gpio_default_para_init(&gpio_init_struct);
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  gpio_init_struct.gpio_pins = GPIO_PINS_8;
  gpio_init(GPIOA, &gpio_init_struct);
  gpio_init_struct.gpio_pins = GPIO_PINS_1 | GPIO_PINS_6 | GPIO_PINS_7 | GPIO_PINS_10 | GPIO_PINS_11;
  gpio_init(GPIOB, &gpio_init_struct);

  /* enable spim, and select pb10, pb11 as spim io */
  gpio_pin_remap_config(EXT_SPIM_GMUX_1001, TRUE);

  /* in this example, use on-board en25qh128a as spim flash */
  flash_spim_model_select(FLASH_SPIM_MODEL1);

  /* for model 1 flash, a delay needs to be added */
  delay_ms(20);
  
  /* unlock the spim flash program erase controller */
  while(flash_flag_get(FLASH_SPIM_OBF_FLAG));
  flash_spim_unlock();
  while(FLASH->ctrl3_bit.oplk);

  /* if the data written to spim flash need to be scrambled, please specify the scrambled range */
  flash_spim_encryption_range_set(0);
  
}

/**
  * @brief  read one sector from a specified address in spim flash
  * @param  address: specifies the sector starting address
  * @param  sector_size: sector size in bytes
  * @param  buf: the content read from spim flash
  * @retval none
  */
void sector_read(uint32_t address, uint32_t sector_size, uint8_t *buf)
{
  while(sector_size)
  {
    *(uint32_t *)buf = *(uint32_t *)address;
    sector_size -= sizeof(uint32_t);
    address += sizeof(uint32_t);
    buf += sizeof(uint32_t);
  }
}

void w25qxx_flash_read(uint32_t address, uint8_t *buf, uint32_t size)
{
    uint32_t len = size&3;
    flash_status_type status = FLASH_OPERATE_DONE;
    
    address += SPIM_START_ADDR;
    for(int i=0; i<(size>>2); i++)
    {
        *(uint32_t *)buf = *(uint32_t *)address;
        address += sizeof(uint32_t);
        buf += sizeof(uint32_t);
    }
    if(len > 0)
    {
        uint32_t dat = *(uint32_t *)address;
        for(int i=0; i<len; i++)
        {
            buf[i] = (uint8_t)dat;
            dat >>= 8;
        }
    }
}

void w25qxx_flash_write(uint32_t address,const uint8_t *buf, uint32_t size)
{
    uint32_t len = size&3;
    uint32_t *word = (uint32_t*)buf;
    flash_status_type status = FLASH_OPERATE_DONE;
    
    FLASH->ctrl3_bit.fprgm = TRUE;
    address += SPIM_START_ADDR;
    for(int i=0; i<(size>>2); i++)
    {
        *(__IO uint32_t*)address = *word;
        address += sizeof(uint32_t);
        word ++;
    }
    
    if(len > 0)
    {
        uint32_t dat = *word;
        
        dat |= 0xFFFFFFFF << ((4-len)*8);
        *(__IO uint32_t*)address = dat;
        address += sizeof(uint32_t);
        word ++;
    }
    status = flash_spim_operation_wait_for(SPIM_PROGRAMMING_TIMEOUT);
    if((status == FLASH_PROGRAM_ERROR) || (status == FLASH_EPP_ERROR))
    flash_flag_clear(FLASH_PRGMERR_FLAG | FLASH_EPPERR_FLAG);
    /* disable the fprgm bit */
    FLASH->ctrl3_bit.fprgm = FALSE;
}




void w25qxx_erase_sector(uint32_t sector_address)
{
    flash_status_type status = FLASH_OPERATE_DONE;
    
    sector_address += SPIM_START_ADDR;
    
    FLASH->ctrl3_bit.secers = TRUE;
    FLASH->addr3 = sector_address;
    FLASH->ctrl3_bit.erstr = TRUE;
    /* wait for operation to be completed */
    status = flash_spim_operation_wait_for(SPIM_ERASE_TIMEOUT);
    /* disable the secers bit */
    FLASH->ctrl3_bit.secers = FALSE;
    
    if((status == FLASH_PROGRAM_ERROR) || (status == FLASH_EPP_ERROR))
    flash_flag_clear(FLASH_PRGMERR_FLAG | FLASH_EPPERR_FLAG);
}



